package com.szbber.commen.base

import android.content.Context
import androidx.lifecycle.LifecycleObserver
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.blankj.utilcode.utils.NetworkUtils
import com.blankj.utilcode.utils.ToastUtils
import com.szbber.commen.dialog.LoadingDialog
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import retrofit2.adapter.rxjava2.HttpException
import com.szbber.medical.commen.R
import java.io.EOFException
import java.net.ConnectException
import java.net.SocketException
import java.net.SocketTimeoutException
import java.net.UnknownHostException
import javax.net.ssl.SSLException

//实现LifecycleObserver接口，是为了通过activity的lifecycle.addObserver(LifecycleObserver) 绑定到生命周期中
open class BaseViewModel : ViewModel(), LifecycleObserver {


    private var loadingDialog: LoadingDialog? = null

    fun showLoadingDialog(context: Context?) {
        dismissLoadingDialog()
        val builder: LoadingDialog.Builder =
            LoadingDialog.Builder(context)
                .setMessage(context?.getString(R.string.common_loading))
                .setCancelable(true)
        loadingDialog = builder.create()
        loadingDialog?.show()
    }
    fun dismissLoadingDialog() {
        if (null != loadingDialog && loadingDialog!!.isShowing) {
            loadingDialog?.dismiss()
            loadingDialog = null
        }
    }

//    viewModelScope是ViewModel中的成员对象，该对象实现了CoroutineScope接口
//    suspend CoroutineScope.() -> Unit, suspend是kotlin线程挂起的标识，实际上去走了await()方法
//    CoroutineScope.() -> Unit 代表一个方法体，并且该方法体对象是CoroutineScope接口对象，主要是规范方法体类型，可除去CoroutineScope.
    fun launchUI(block: suspend CoroutineScope.() -> Unit) = viewModelScope.launch {
        try {
            block()
        } catch (e: Exception) {
            e.printStackTrace()
        }

    }

//    相比上个方法，主要是多了 withContext(Dispatchers.IO)，目的是切换到子线程做耗时操作
    fun launchIO(block: suspend CoroutineScope.() -> Unit) = viewModelScope.launch {
        withContext(Dispatchers.IO) {
            try {
                block()
            } catch (e: Exception) {
                e.printStackTrace()
            }
        }
    }

//    errorHandler 是为了统一处理网络异常
    fun launchIO(context: Context?,
        block: suspend CoroutineScope.() -> Unit={},
        errorHandler: () -> Unit={ }
    ) = viewModelScope. launch {
        withContext(Dispatchers.IO) {
            try {
                if (NetworkUtils.isConnected()) {
                    showLoadingDialog(context)
                    block()
                } else {
                    dismissLoadingDialog()
                    ToastUtils.showShortToastSafe("300")
//                    errorHandler(300, "No internet connection")
                }
            } catch (e: Exception) {
                dismissLoadingDialog()
                handlerErrorCode(e)
                e.printStackTrace()
            }finally {
                //....
                dismissLoadingDialog()
            }
        }
    }

    private fun handlerErrorCode(
        e: Exception
    ) {
        when (e) {
            is HttpException -> {
                ToastUtils.showShortToastSafe("300")
//                errorHandler(e.code(), e.message())
            }
            is UnknownHostException -> {
                ToastUtils.showShortToastSafe("400")
//                errorHandler(404, "Unable to connect to server")
            }
            is SocketTimeoutException -> {
                ToastUtils.showShortToastSafe("408")
//                errorHandler(408, "Socket time out")//访问超时
            }
            is ConnectException -> {
                ToastUtils.showShortToastSafe("404")
//                errorHandler(404, "Connect exception")
            }
            is SocketException -> {
                ToastUtils.showShortToastSafe("500")
//                errorHandler(500, "Socket exception")
            }
            is EOFException -> {
                ToastUtils.showShortToastSafe("500")
//                errorHandler(500, "EOF exception") //连接意外中断
            }
            is IllegalArgumentException -> {
                ToastUtils.showShortToastSafe("400")
//                errorHandler(400, "Illegal argument exception")//参数错误
            }
            is SSLException -> {
                ToastUtils.showShortToastSafe("401")
//                errorHandler(401, "SSL exception")//证书错误
            }
            is NullPointerException -> {
                ToastUtils.showShortToastSafe("600")
//                errorHandler(600, "Null pointer exception")
            }
            else -> {
                ToastUtils.showShortToastSafe("700")
//                errorHandler(700, "Unknown exception")
            }
        }
    }

//    fun Map<String, Any>.getBody(): RequestBody {
//        return Gson().toJson(this).toRequestBody("application/json".toMediaTypeOrNull())
//    }

    data class ErrorHandler(val code: Int, val message: String)


}